/*
 *
 * Date: 2017年11月15日
 * Time: 下午2:15:55
 *
 */

package com.lmx.local.business;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.lmx.common.util.CommonUtil;
import com.lmx.common.util.PropertiesFileUtil;
import com.lmx.local.SocketClient;
import com.lmx.persistence.service.local.LocalCameraService;
import com.lmx.repoDomain.local.tmodel.Camera;
import com.lmx.repoDomain.tmodel.LsMessage;

import net.bramp.ffmpeg.FFmpegExecutor;
import net.bramp.ffmpeg.FFmpegUtils;
import net.bramp.ffmpeg.FFprobe;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import net.bramp.ffmpeg.job.FFmpegJob;
import net.bramp.ffmpeg.probe.FFmpegProbeResult;
import net.bramp.ffmpeg.progress.Progress;
import net.bramp.ffmpeg.progress.ProgressListener;

/**
 * 视频处理服务
 * 
 * @author 梁慕学
 * @version 1.00
 */
@Service
@Scope("singleton")
public class VideoProcessor {
	private static final Logger log = LoggerFactory.getLogger(VideoProcessor.class);

	private Properties properties = PropertiesFileUtil.getApplicationProperties();

	@Autowired
	protected LocalCameraService cameraService;

	@Autowired
	protected SocketClient client;

	private FFmpegExtender ffmpeg;
	
	private List<Camera> cameraList = new ArrayList<Camera>();// 在线设备列表
	/*
	 * 初始化入口，从数据库中载入摄像头列表
	 */

	public void init() {
		// 使用ffmpeg cli项目，进行fmpeg的流处理
		// 进行ffmpeg全局对象的初始化
		String ffmpegCommandPath = properties.getProperty("local.camera.ffmpegCommandPath");
		// 定义监听者
		CustomRunProcessFunc func = new CustomRunProcessFunc();
		// 把监听者绑定到ffmpeg对象
		try {
			this.ffmpeg = new FFmpegExtender(ffmpegCommandPath, func);
		} catch (IOException e) {
			log.error("ffmpeg init fail", e);
		}
	}

	/*
	 * 启动远程推拉流
	 */
//	public void startRemoteLive(WebSocketSession session,String businessId, String code) throws IOException  {
	public void startRemoteLive(String businessId, String code) throws IOException  {	
		log.warn("startRemoteLive 1");
		if (this.ffmpeg == null) {
			log.warn("startRemoteLive 2");
			this.init();
		}
		int resFlag = 0;
		Camera camera = this.cameraService.findByCode(code);
		log.warn("startRemoteLive 3");
		if (camera == null) {
			log.warn("no this camera");
			LsMessage msg = new LsMessage();
			msg.setCode("1001");
			msg.setBusinessId(businessId);
			msg.setDeviceCode(code);
			msg.setCreateTime(CommonUtil.getCurrTimes());
			msg.setSuccess(0);// 推流失败
			client.sendMessage(msg);
			return;
		}
		log.warn("startRemoteLive 4");
//		String command = this.createStreamCommand(camera);
//		log.debug("command:" + command);
		String ffprobeCommandPath = properties.getProperty("local.camera.ffprobeCommandPath");
		FFprobe ffprobe = new FFprobe(ffprobeCommandPath);
		FFmpegExecutor executor = new FFmpegExecutor(this.ffmpeg, ffprobe);
		// 摄像头rtsp地址
		String cameraAddress = "rtsp://" + camera.getAccessName() + ":" + camera.getAccessPass() + "@" + camera.getIp()
				+ ":" + camera.getPort().toString() 
				+ "/"+camera.getUri();
				//"/h264"
				//+"/ch1/main/av_stream";
		// cameraAddress = "D:/temp/video/test.mp4";
		String remoteUrl = properties.getProperty("local.camera.remoteUrl");
		// 输出流，远程视频服务地址
		String rtmpLink = remoteUrl + "/" + camera.getCode();
		log.debug("remoteUrl:" + remoteUrl);
		log.debug("cameraAddress:" + cameraAddress);
		FFmpegProbeResult in = ffprobe.probe(cameraAddress);
		log.debug("rtmpLink:" + rtmpLink);
		FFmpegBuilder builder = new FFmpegBuilder().addExtraArgs("-an").setInput(in).addOutput(rtmpLink)
				.setFormat("flv").setAudioCodec("aac").setVideoCodec("libx264").addExtraArgs("-strict").addExtraArgs("-2").setVideoResolution(640, 480).done();
		// 创建监听器
		CustomRunProcessFunc cpf = (CustomRunProcessFunc) this.ffmpeg.getFunc();
		LiveStreamListener listener = new LiveStreamListener(camera.getIp(), camera.getCode());
//		listener.setSession(session);
//		liveStreamListener.setIp(camera.getIp());
//		liveStreamListener.setDeviceCode(camera.getCode());
		cpf.add(listener);
		// 进行推拉流
		FFmpegJob job = executor.createJob(builder, new ProgressListener() {
			// Using the FFmpegProbeResult determine the duration of the input
			final double duration_ns = in.getFormat().duration * TimeUnit.SECONDS.toNanos(1);
			int resFlag = 0;

			@Override
			public void progress(Progress progress) {
				String progressStatus = progress.status.toString();
				//log.debug("progress.status:" + progress.status);
				if ("continue".equals(progressStatus) && resFlag == 0) {
					// 启动云端流监听
					LiveStreamListener listener = VideoProcessor.this.ffmpeg.getListenerFromCode(camera.getCode());
					listener.setBusinessId(businessId);
					listener.setDeviceUri(camera.getUri());
					log.debug("listener is:" + listener);
					if (listener != null) {
						log.debug("start live check");
						listener.startRemoteLiveCheck(ffmpeg);
					} else {
						log.warn("no listener to check:" + camera.getCode());
					}
					 resFlag = 1;
					 log.debug("session.sendMessage:" +
					 CommonUtil.getCurrTime());
					 LsMessage msg = new LsMessage();
					 msg.setCode("1002");
					 msg.setBusinessId(businessId);
					 msg.setDeviceCode(code);
					 msg.setCreateTime(CommonUtil.getCurrTimes());
					 msg.setSuccess(1);
					 //发送已经开始推流成功指令，此时不一定能拉流
					 client.sendMessage(msg);
				}
				double percentage = progress.out_time_ns / duration_ns;
				log.debug(String.format("[%.0f%%] status:%s frame:%d time:%s ms fps:%.0f speed:%.2fx", percentage * 100,
						progress.status, progress.frame,
						FFmpegUtils.toTimecode(progress.out_time_ns, TimeUnit.NANOSECONDS), progress.fps.doubleValue(),
						progress.speed));
			}
		});
		job.run();
	}

	/*
	 * 停止推流
	 * 
	 * @param String code 摄像头序列号
	 */
//	public void stopRemoteLive(WebSocketSession session,String businessId, String code) {
	public void stopRemoteLive(String businessId, String code) {
		log.debug("stopRemoteLive 1" +code);
		CustomRunProcessFunc cpf = (CustomRunProcessFunc) this.ffmpeg.getFunc();
		log.debug("stopRemoteLive 2" +code);
		if(cpf.getListenerFromCode(code)==null||cpf.getListenerFromCode(code).getProcess()==null){
			return;
		}
		cpf.getListenerFromCode(code).getProcess().destroy();
		log.debug("stopRemoteLive 3" +code);
		// 停止推流反馈
		LsMessage msg = new LsMessage();
		msg.setCode("4001");
		msg.setBusinessId(businessId);
		msg.setDeviceCode(code);
		msg.setCreateTime(CommonUtil.getCurrTimes());
		msg.setSuccess(1);
//		log.debug("stopRemoteLive " +msg);
//		log.debug("livetest stop sendMessage1:");
//        String msgStr = JSONObject.fromObject(msg).toString();
//        log.debug("livetest stop sendMessage2:" + msgStr);
//        TextMessage message = new TextMessage(msgStr);
//        log.debug("livetest stop sendMessage:" + msgStr);
//        try {
//            session.sendMessage(message);
//        } catch (IOException e) {
//        	log.error("send msg fail for:" + msgStr,e);
//        }
		client.sendMessage(msg);
	}

	/*
	 * 生成推拉流指令字符串
	 */
	public String createStreamCommand(Camera camera) {
		String remoteUrl = properties.getProperty("local.camera.remoteUrl");
		// 摄像头rtsp地址
		String cameraAddress = "rtsp://" + camera.getAccessName() + ":" + camera.getAccessPass() + "@" + camera.getIp()
				+ ":" + camera.getPort().toString() + "/h264/ch1/main/av_stream";
		// 远程流媒体服务地址
		String rtmpLink = remoteUrl + "/" + camera.getCode();
		String command = "ffmpeg -i";
		String options = "-f flv -r -s -an";
		command = command + " \"" + cameraAddress + "\" " + options + " \"" + rtmpLink + "\"";
		return command;
	}
}
